package com.yonyou.pmclouds.plan.rmiimpl;

import com.alibaba.dubbo.config.annotation.Service;
import com.yonyou.pmclouds.ApplicationConsts;
import com.yonyou.pmclouds.basecom.bp.processor.AuditInfoInsertProcessor;
import com.yonyou.pmclouds.basecom.bp.template.SingleInsertBpTemplate;
import com.yonyou.pmclouds.basecom.consts.BillTypeConst;
import com.yonyou.pmclouds.basecom.exception.BusinessException;
import com.yonyou.pmclouds.basecom.impl.NCCSendMessageService;
import com.yonyou.pmclouds.basecom.runtime.RuntimeEnvironment;
import com.yonyou.pmclouds.outter.user.UserInfoServerQuery;
import com.yonyou.pmclouds.plan.entity.PlanProgressHistoryVO;
import com.yonyou.pmclouds.plan.entity.PlanProgressStatusConst;
import com.yonyou.pmclouds.plan.entity.PlanProgressVO;
import com.yonyou.pmclouds.plan.entity.ProjectPlanVO;
import com.yonyou.pmclouds.plan.mapper.PlanProgressHistoryMapper;
import com.yonyou.pmclouds.plan.mapper.PlanProgressMapper;
import com.yonyou.pmclouds.plan.plandriven.entity.InvokeResultVO;
import com.yonyou.pmclouds.plan.plandriven.entity.NccMessageParamVO;
import com.yonyou.pmclouds.plan.plandriven.entity.PlanDrivenParamVO;
import com.yonyou.pmclouds.plan.plandriven.rmiitf.IPlanDriven;
import com.yonyou.pmclouds.plan.rmiitf.ProjectPlanMaintain;
import com.yonyou.pmclouds.plan.rmiitf.ProjectPlanQuery;
import com.yonyou.pmclouds.project.entity.ProjectVO;
import com.yonyou.pmclouds.project.rmiitf.ProjectSimpleQuery;
import com.yonyou.pmclouds.user.entity.UserInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

/**
 * 驱动计划实现类
 *
 * @author th
 * @date 2019/11/18 11:18
 */
@Slf4j
@Service(interfaceClass = IPlanDriven.class, version = ApplicationConsts.APPLICATION_VERSION, timeout = 10000)
public class PlanDrivenImpl implements IPlanDriven {
    @Autowired
    private ProjectPlanQuery planQuery;
    @Autowired
    private ProjectPlanMaintain planMaintain;
    @Autowired
    private NCCSendMessageService nccSendMessageService;
    @Autowired
    private ProjectSimpleQuery projectSimpleQuery;
    @Autowired
    private PlanProgressMapper progressMapper;
    @Autowired
    private PlanProgressHistoryMapper historyMapper;
    @Autowired
    private UserInfoServerQuery userInfoServerQuery;

    @Override
    public InvokeResultVO drivePlanByMilestoneBill(PlanDrivenParamVO paramVO) {
        if (paramVO == null) {
            log.error("驱动参数VO不能为空");
            return new InvokeResultVO<>(InvokeResultVO.RESULT_FAIL, false, "驱动参数VO不能为空");
        }

        if (StringUtils.isEmpty(paramVO.getPkProject()) || StringUtils.isEmpty(paramVO.getBillType())
                || StringUtils.isEmpty(paramVO.getAction())) {
            log.error("驱动参数，项目:{}、单据类型:{}、动作:{}, 不能为空", paramVO.getPkProject(), paramVO.getBillType(), paramVO.getAction());
            return new InvokeResultVO<>(InvokeResultVO.RESULT_FAIL, false, "驱动参数，项目、单据类型、动作，不能为空");
        }

        try {
            String pkProject = paramVO.getPkProject();
            // 如果是nc单据驱动，获取同步到友工程的项目主键
            if (!PlanDrivenParamVO.SRC_PMC.equals(paramVO.getSrcType())) {
                // 查询nc同步过来的项目
                ProjectVO projectVO = projectSimpleQuery.queryByPkSrc(RuntimeEnvironment.getTenantId(), paramVO.getPkProject());
                if (projectVO != null) {
                    pkProject = projectVO.getPkProject();
                } else {
                    return new InvokeResultVO<>(InvokeResultVO.RESULT_FAIL, false, "未查询到友工程里的项目");
                }
            }

            // 查询项目下关联了单据的末级计划
            ProjectPlanVO[] leafPlans = planQuery.queryByProjectAndRelatedBillType(pkProject, paramVO.getBillType(),
                    paramVO.getTransiType());
            if (ArrayUtils.isEmpty(leafPlans))
                return new InvokeResultVO<>(InvokeResultVO.RESULT_FAIL, false, "项目计划未关联单据");

            // 校验计划是否需要驱动或回滚
            ProjectPlanVO[] planVOs = filterLeafPlans(leafPlans, paramVO.getAction());
            if (ArrayUtils.isEmpty(planVOs))
                return new InvokeResultVO<>(InvokeResultVO.RESULT_FAIL, false, "该项目没有计划需要驱动或回滚");

            // 更新末级计划进度
            updateProgress(planVOs, paramVO, true);
            // 驱动或回滚计划
            drivePlan(paramVO, planVOs);
        } catch (BusinessException e) {
            log.error("单据驱动计划失败，单据来源：{}，单据类型：{}，单据pk：{}，nc项目：{}",
                    paramVO.getSrcType(), paramVO.getBillType(), paramVO.getPkBill(), paramVO.getPkProject());
            log.error("单据驱动计划失败", e);

            return new InvokeResultVO<>(InvokeResultVO.RESULT_FAIL, false, "单据驱动计划失败，" + e.getMessage());
        }

        return new InvokeResultVO<>(InvokeResultVO.RESULT_OK, true, null);
    }

    @Override
    public InvokeResultVO drivePlansByProgress(ProjectPlanVO[] leafPlanVOs) throws BusinessException {
        if (ArrayUtils.isEmpty(leafPlanVOs))
            return new InvokeResultVO<>(InvokeResultVO.RESULT_FAIL, false, "参数不能为空");

        try {
            PlanDrivenParamVO paramVO = new PlanDrivenParamVO();
            paramVO.setAction(PlanDrivenParamVO.ACTION_DRIVE);
            paramVO.setUserId(leafPlanVOs[0].getPlanFinisher());
            drivePlan(paramVO, leafPlanVOs);
        } catch (BusinessException e) {
            log.error("进度驱动计划失败", e);
            return new InvokeResultVO<>(InvokeResultVO.RESULT_FAIL, false, "进度驱动计划失败，" + e.getMessage());
        }

        return new InvokeResultVO<>(InvokeResultVO.RESULT_OK, true, null);
    }

    @Override
    public InvokeResultVO sendMessageManually(String[] planIds) throws BusinessException {
        if (ArrayUtils.isEmpty(planIds))
            return new InvokeResultVO<>(InvokeResultVO.RESULT_FAIL, false, "计划主键为空，消息发送失败。");

        List<ProjectPlanVO> projectPlanVOs = planQuery.queryByPkPlans(planIds);
        if (CollectionUtils.isEmpty(projectPlanVOs))
            return new InvokeResultVO<>(InvokeResultVO.RESULT_FAIL, false, "未查询到计划，消息发送失败。");

        ProjectVO projectVO = projectSimpleQuery.queryProject(projectPlanVOs.get(0).getPkProject());
        NccMessageParamVO messageParamVO = convertToMessageParamVO(projectPlanVOs, projectVO);
        if (nccSendMessageService.sendMessageToNCC(messageParamVO)) {
            return new InvokeResultVO<>(InvokeResultVO.RESULT_OK, true, null);
        }

        return new InvokeResultVO<>(InvokeResultVO.RESULT_FAIL, false, "消息发送失败");
    }

    /**
     * 过滤计划
     * 驱动计划，已完成的计划不驱动
     * 回滚计划，未完成的计划不回滚，驱动后填报过的计划不回滚
     *
     * @param leafPlans
     * @param action
     * @return
     */
    private ProjectPlanVO[] filterLeafPlans(ProjectPlanVO[] leafPlans, String action) {
        List<ProjectPlanVO> result = new ArrayList<>();
        // 回滚时，根计划map
        Map<String, ProjectPlanVO> planMap = new HashMap<>();

        for (ProjectPlanVO vo : leafPlans) {
            if (PlanDrivenParamVO.ACTION_DRIVE.equals(action) && vo.getCompletedStatus() != PlanProgressStatusConst.PLAN_COMPLETED) {
                result.add(vo);
            } else if (PlanDrivenParamVO.ACTION_ROLLBACK.equals(action) && vo.getCompletedStatus() == PlanProgressStatusConst.PLAN_COMPLETED) {
                planMap.put(vo.getPkPlan(), vo);
            }
        }

        if (PlanDrivenParamVO.ACTION_ROLLBACK.equals(action) && planMap.size() > 0) {
            // 查询已驱动的计划的进度反馈记录
            PlanProgressHistoryVO[] historyVOs = historyMapper.queryProgressHistoryByPlans(planMap.keySet().toArray(new String[0]));
            if (ArrayUtils.isEmpty(historyVOs))
                return result.toArray(new ProjectPlanVO[0]);

            Map<String, List<PlanProgressHistoryVO>> planToHistory = new HashMap<>();
            for (PlanProgressHistoryVO historyVO : historyVOs) {
                if (planToHistory.get(historyVO.getPkPlan()) == null)
                    planToHistory.put(historyVO.getPkPlan(), new ArrayList<PlanProgressHistoryVO>());

                planToHistory.get(historyVO.getPkPlan()).add(historyVO);
            }

            for (Map.Entry<String, List<PlanProgressHistoryVO>> entry : planToHistory.entrySet()) {
                String pkPlan = entry.getKey();
                List<PlanProgressHistoryVO> historyVOList = entry.getValue();
                if (CollectionUtils.isEmpty(historyVOList))
                    continue;

                // 按创建时间逆序排
                Collections.sort(historyVOList, new Comparator<PlanProgressHistoryVO>() {
                    @Override
                    public int compare(PlanProgressHistoryVO o1, PlanProgressHistoryVO o2) {
                        return -(o1.getCreationtime().compareTo(o2.getCreationtime()));
                    }
                });
                // 最新的反馈进度是100且描述是“单据驱动完成”，则认为该计划需要回滚
                if (100 == historyVOList.get(0).getProgress() && "单据驱动完成".equals(historyVOList.get(0).getDescription()))
                    result.add(planMap.get(pkPlan));
            }
        }

        return result.toArray(new ProjectPlanVO[0]);
    }

    /**
     * 驱动或回滚计划
     *
     * @param paramVO
     * @param leafPlans
     */
    private void drivePlan(PlanDrivenParamVO paramVO, ProjectPlanVO[] leafPlans) throws BusinessException {
        // 单据弃审，回滚计划
        if (PlanDrivenParamVO.ACTION_ROLLBACK.equals(paramVO.getAction())) {
            // 待回滚的计划
            List<ProjectPlanVO> rollBackPlans = new ArrayList<>();
            // 获取要回滚的末级计划、父计划
            getRollbackPlans(leafPlans, rollBackPlans);
            // 回滚，更新计划完成状态、完成人
            updatePlan(rollBackPlans, PlanProgressStatusConst.PLAN_NOT_COMPLETED, null, null);
        } else if (PlanDrivenParamVO.ACTION_DRIVE.equals(paramVO.getAction())) { // 单据或进度填报驱动
            // 待驱动的计划集合
            List<ProjectPlanVO> notDrivenPlanList = new ArrayList<>();
            Set<String> notDrivenPkPlanSet = new HashSet<>();
            // 迭代获取要驱动的父计划
            getNotDrivenParentPlan(leafPlans, notDrivenPlanList, notDrivenPkPlanSet);
            // 获取计划完成人
            String planFinisher = getPlanFinisher(paramVO);
            // 驱动计划
            updatePlan(notDrivenPlanList, PlanProgressStatusConst.PLAN_COMPLETED, planFinisher, paramVO.getPkBill());
            // 通知后置计划
            List<ProjectPlanVO> postPlans = notifyPostPlan(notDrivenPlanList);
            // 更新后置计划的进度
            if (CollectionUtils.isNotEmpty(postPlans))
                updateProgress(postPlans.toArray(new ProjectPlanVO[0]), paramVO, false);
        }
    }

    /**
     * 获取计划完成人
     *
     * @param paramVO
     * @return
     */
    private String getPlanFinisher(PlanDrivenParamVO paramVO) throws BusinessException {
        String planFinisher = null;
        if (StringUtils.isNotEmpty(paramVO.getUserId())) {
            planFinisher = paramVO.getUserId();
        } else if (StringUtils.isNotEmpty(paramVO.getUserMobile())) {
            UserInfo userInfo = userInfoServerQuery.getUserIdByContact(paramVO.getUserMobile(), null);
            if (userInfo != null)
                planFinisher = userInfo.getUserId();
        }

        return planFinisher;
    }

    /**
     * 获取要回滚的末级计划、父计划
     *
     * @param plans
     * @param rollBackPlans
     */
    private void getRollbackPlans(ProjectPlanVO[] plans, List<ProjectPlanVO> rollBackPlans) {
        if (ArrayUtils.isEmpty(plans))
            return;

        Set<String> parentSet = new HashSet<>();
        for (ProjectPlanVO planVO : plans) {
            rollBackPlans.add(planVO);
            if (StringUtils.isNotEmpty(planVO.getPkParent()))
                parentSet.add(planVO.getPkParent());
        }

        if (parentSet.isEmpty())
            return;

        List<ProjectPlanVO> parentPlans = planQuery.queryByPkPlans(parentSet.toArray(new String[0]));
        if (CollectionUtils.isEmpty(parentPlans))
            return;

        // 递归
        getRollbackPlans(parentPlans.toArray(new ProjectPlanVO[0]), rollBackPlans);
    }

    /**
     * 驱动计划，更新计划完成状态、完成人
     *  @param drivenPlanList
     * @param completeStatus
     * @param pkBill
     */
    private void updatePlan(List<ProjectPlanVO> drivenPlanList, Byte completeStatus, String finisher, String pkBill) throws BusinessException {
        if (CollectionUtils.isEmpty(drivenPlanList))
            return;

        for (ProjectPlanVO vo : drivenPlanList) {
            vo.setCompletedStatus(completeStatus);
            if (vo.getChildCount() == 0) {
                vo.setPlanFinisher(finisher);
                vo.setRelatedPkBill(pkBill);
            }
        }
        // 更新
        planMaintain.updateVOs(drivenPlanList.toArray(new ProjectPlanVO[0]));
    }

    /**
     * 向后置计划发送待办通知
     *
     * @param planVOs
     * @return 后置计划
     * @throws BusinessException
     */
    private List<ProjectPlanVO> notifyPostPlan(List<ProjectPlanVO> planVOs) throws BusinessException {
        if (CollectionUtils.isEmpty(planVOs))
            return new ArrayList<>();

        Set<String> pkPlanSet = new HashSet<>();
        for (ProjectPlanVO planVO : planVOs) {
            pkPlanSet.add(planVO.getPkPlan());
        }

        ProjectVO projectVO = projectSimpleQuery.queryProject(planVOs.get(0).getPkProject());
        // 查询项目下已驱动计划的后置计划
        List<ProjectPlanVO> postPlans = planQuery.queryByProjectAndDependPlan(projectVO.getPkProject(),
                pkPlanSet.toArray(new String[0]));

        if (CollectionUtils.isEmpty(postPlans))
            return new ArrayList<>();

        // 不是NC同步的项目不需要发送消息通知
        if (projectVO == null || StringUtils.isEmpty(projectVO.getPkSrc()))
            return postPlans;

        // 构造待办消息参数，发送消息通知
        NccMessageParamVO messageParamVO = convertToMessageParamVO(postPlans, projectVO);
        nccSendMessageService.sendMessageToNCC(messageParamVO);
        return postPlans;
    }

    /**
     * 计划转换为消息VO
     *
     * @param plans
     * @param projectVO
     * @return
     */
    private NccMessageParamVO convertToMessageParamVO(List<ProjectPlanVO> plans, ProjectVO projectVO) throws BusinessException {
        NccMessageParamVO paramVO = new NccMessageParamVO();
        List<NccMessageParamVO.MessageVO> messageVOs = new ArrayList<>();
        if (CollectionUtils.isEmpty(plans))
            return paramVO;

        // 根计划pk与名称的映射
        Map<String, String> rootPlanToName = queryRootPlanName(plans);
        // 查询负责人手机号
        Map<String, String> managerMobileMap = queryManagerMobile(plans);
        // 构造待办消息
        for (ProjectPlanVO vo : plans) {
            // 未关联NC单据或同时没选择部门、负责人的计划不发送消息
            boolean notSend = StringUtils.isEmpty(vo.getRelatedBillType()) || BillTypeConst.WORKSTART_BILLTYPE.equals(vo.getRelatedBillType())
                    || BillTypeConst.COMPREHENSIVE_ACCEPTANCE_BILLTYPE.equals(vo.getRelatedBillType()) || StringUtils.isEmpty(vo.getDependPlan())
                    || (StringUtils.isEmpty(vo.getManager()) && StringUtils.isEmpty(vo.getPkDepartment()));
            if (notSend)
                continue;

            // 构造待办消息体
            NccMessageParamVO.MessageVO messageVO = new NccMessageParamVO.MessageVO();
            messageVO.setBuziName(rootPlanToName.get(vo.getPkRoot()));
            messageVO.setBillType(vo.getRelatedBillType());
            messageVO.setPkDept(vo.getPkDepartment());
            if (StringUtils.isNotEmpty(vo.getManager()))
                messageVO.setUserMobile(managerMobileMap.get(vo.getManager()));
            messageVOs.add(messageVO);
        }

        paramVO.setPkOrg(projectVO.getPkOrg());
        paramVO.setPkProject(projectVO.getPkSrc());
        paramVO.setInfos(messageVOs);
        return paramVO;
    }

    /**
     * 查询负责人手机号
     *
     * @param plans
     * @return
     */
    private Map<String, String> queryManagerMobile(List<ProjectPlanVO> plans) {
        Map<String, String> result = new HashMap<>();
        // 负责人pk集合
        Set<String> managerSet = new HashSet<>();
        for (ProjectPlanVO planVO : plans) {
            // 未关联单据的计划不发送消息
            if (StringUtils.isEmpty(planVO.getManager()) || StringUtils.isEmpty(planVO.getRelatedBillType())
                    || StringUtils.isEmpty(planVO.getDependPlan()))
                continue;

            managerSet.add(planVO.getManager());
        }

        if (managerSet.isEmpty())
            return result;

        UserInfo[] userInfos = userInfoServerQuery.queryUsers(managerSet.toArray(new String[0]));
        if (ArrayUtils.isEmpty(userInfos))
            return result;

        for (UserInfo user : userInfos) {
            result.put(user.getUserId(), user.getUserMobile());
        }

        return result;
    }

    /**
     * 查询根计划的名称
     *
     * @param plans
     * @return
     */
    private Map<String, String> queryRootPlanName(List<ProjectPlanVO> plans) {
        // 根计划的pk集合
        Set<String> rootPlanSet = new HashSet<>();
        for (ProjectPlanVO planVO : plans) {
            // 未关联单据的计划不发送消息
            if (StringUtils.isEmpty(planVO.getPkRoot()) || StringUtils.isEmpty(planVO.getRelatedBillType())
                    || StringUtils.isEmpty(planVO.getDependPlan()))
                continue;

            rootPlanSet.add(planVO.getPkRoot());
        }

        // 根计划pk与名称的映射
        Map<String, String> rootPlanToName = new HashMap<>();
        if (rootPlanSet.isEmpty())
            return rootPlanToName;

        List<ProjectPlanVO> rootPlans = planQuery.queryByPkPlans(rootPlanSet.toArray(new String[0]));
        if (CollectionUtils.isNotEmpty(rootPlans)) {
            for (ProjectPlanVO vo : rootPlans) {
                rootPlanToName.put(vo.getPkPlan(), vo.getSname());
            }
        }

        return rootPlanToName;
    }

    /**
     * 检查同级计划进度情况，决定是否驱动父计划完成，若父计划要驱动，添加到drivenPlanList，以此类推往上检查
     *
     * @param planVOs
     * @param drivenPlanList 要驱动的计划VO集合
     * @param drivenPkPlanSet 要驱动的计划主键集合
     */
    private void getNotDrivenParentPlan(ProjectPlanVO[] planVOs, List<ProjectPlanVO> drivenPlanList, Set<String> drivenPkPlanSet) {
        // 获取父计划
        Set<String> parentSet = new HashSet<>();
        for (ProjectPlanVO planVO : planVOs) {
            drivenPlanList.add(planVO);
            drivenPkPlanSet.add(planVO.getPkPlan());
            if (StringUtils.isNotEmpty(planVO.getPkParent()))
                parentSet.add(planVO.getPkParent());
        }

        if (parentSet.isEmpty())
            return;

        // 获取parent下的所有子计划
        Map<String, List<ProjectPlanVO>> childrenPlans = planQuery.queryChildPlanByParents(parentSet.toArray(new String[0]));
        // 当前递归要驱动的父计划主键集合
        Set<String> drivenParentSet = new HashSet<>();
        for (Map.Entry<String, List<ProjectPlanVO>> entry : childrenPlans.entrySet()) {
            // 是否要驱动父计划
            boolean isParentDriven = true;
            List<ProjectPlanVO> children = entry.getValue();
            // 当前计划是否完成
            boolean isCompleted = false;
            for (ProjectPlanVO child : children) {
                // drivenPkPlanSet包含当前计划或者计划状态为已完成，则认为计划完成
                isCompleted = (drivenPkPlanSet.contains(child.getPkPlan())) ||
                        (PlanProgressStatusConst.PLAN_COMPLETED == child.getCompletedStatus());
                if (!isCompleted) {
                    isParentDriven = false;
                    break;
                }
            }

            if (!isParentDriven)
                continue;

            drivenParentSet.add(entry.getKey());
            drivenPkPlanSet.add(entry.getKey());
        }

        if (drivenParentSet.isEmpty())
            return;

        // 查询要驱动的计划
        List<ProjectPlanVO> parentList = planQuery.queryByPkPlans(drivenParentSet.toArray(new String[0]));
        if (CollectionUtils.isEmpty(parentList))
            return;

        // 递归
        getNotDrivenParentPlan(parentList.toArray(new ProjectPlanVO[0]), drivenPlanList, drivenPkPlanSet);
    }

    /**
     * 计划完成，更新进度
     *
     *  @param planVOs 要更新进度的计划
     * @param paramVO
     * @param beforeDrive 是否驱动前。true驱动前，更新计划进度为100，false驱动后，更新后置计划开始时间为当前时间
     */
    private void updateProgress(ProjectPlanVO[] planVOs, PlanDrivenParamVO paramVO, boolean beforeDrive) throws BusinessException {
        if (!PlanDrivenParamVO.ACTION_DRIVE.equals(paramVO.getAction()) || ArrayUtils.isEmpty(planVOs))
            return;

        // 当前计划pk与VO的映射
        Map<String, ProjectPlanVO> planToVOMap = new HashMap<>();
        for (ProjectPlanVO vo : planVOs) {
            if (vo.getChildCount() != 0)
                continue;

            planToVOMap.put(vo.getPkPlan(), vo);
        }

        // 查询更新前计划关联的进度
        PlanProgressVO[] oldProgressVOs = planQuery.queryProgressByPlans(planToVOMap.keySet().toArray(new String[0]));
        Map<String, PlanProgressVO> planToOldProgress = new HashMap<>();
        if (ArrayUtils.isNotEmpty(oldProgressVOs)) {
            for (PlanProgressVO progressVO : oldProgressVOs) {
                planToOldProgress.put(progressVO.getPkPlan(), progressVO);
            }
        }

        // 新增的进度集合、更新的进度集合
        List<PlanProgressVO> insertProgressList = new ArrayList<>(), updateProgressList = new ArrayList<>();
        findInsertAndUpdateProgressList(planToVOMap, planToOldProgress, insertProgressList, updateProgressList, beforeDrive);
        if (insertProgressList.size() > 0) {
            for (PlanProgressVO vo : insertProgressList) {
                progressMapper.insert(vo);
            }
        }

        if (updateProgressList.size() > 0) {
            for (PlanProgressVO vo : updateProgressList) {
                progressMapper.updatePlanProgress(vo);
            }
        }

        // 新增反馈记录
        insertProgressHistory(insertProgressList, updateProgressList, beforeDrive);
    }

    /**
     * 新增反馈记录
     *  @param insertProgressList
     * @param updateProgressList
     * @param beforeDrive
     */
    private void insertProgressHistory(List<PlanProgressVO> insertProgressList, List<PlanProgressVO> updateProgressList,
                                       boolean beforeDrive) throws BusinessException {
        if (CollectionUtils.isEmpty(insertProgressList) && CollectionUtils.isEmpty(updateProgressList))
            return;

        List<PlanProgressVO> allProgressList = new ArrayList<>();
        allProgressList.addAll(insertProgressList);
        allProgressList.addAll(updateProgressList);
        List<PlanProgressHistoryVO> historyVOS = new ArrayList<>();
        for (PlanProgressVO progressVO : allProgressList) {
            PlanProgressHistoryVO historyVO = PlanProgressHistoryVO.convertFromProgress(progressVO);
            historyVOS.add(historyVO);
        }

        // 新增计划反馈记录
        SingleInsertBpTemplate<PlanProgressHistoryVO> historyBp = new SingleInsertBpTemplate<>(historyMapper);
        historyBp.addBeforeProcessor(new AuditInfoInsertProcessor<PlanProgressHistoryVO>());
        for (PlanProgressHistoryVO historyVO : historyVOS) {
            if (beforeDrive) {
                historyVO.setDescription("单据驱动完成");
            } else {
                historyVO.setDescription("前置计划完成，计划开始执行");
            }

            historyBp.insert(historyVO);
        }
    }

    /**
     * 获取计划要新增、更新的进度列表
     *  @param planToVOMap
     * @param planToOldProgress
     * @param insertProgressList
     * @param updateProgressList
     * @param beforeDrive
     */
    private void findInsertAndUpdateProgressList(Map<String, ProjectPlanVO> planToVOMap, Map<String, PlanProgressVO> planToOldProgress,
                                                 List<PlanProgressVO> insertProgressList, List<PlanProgressVO> updateProgressList, boolean beforeDrive) {
        String pkPlan;
        PlanProgressVO progressVO;
        String userId = RuntimeEnvironment.getLoginUserId();
        Date today = new Date();
        // 遍历当前计划，填充新增、更新进度集合
        for (Map.Entry<String, ProjectPlanVO> planVOEntry : planToVOMap.entrySet()) {
            pkPlan = planVOEntry.getKey();
            if (planToOldProgress.containsKey(pkPlan)) {
                progressVO = planToOldProgress.get(pkPlan);
                if (beforeDrive) {
                    progressVO.setProgress(100);
                    progressVO.setEndDate(today);
                } else {
                    // 更新后置计划进度为0，实际开始时间为当日
                    progressVO.setProgress(0);
                    progressVO.setStartDate(today);
                    progressVO.setEndDate(null);
                }

                progressVO.setLastSubmitDate(today);
                progressVO.setModifytime(today);
                progressVO.setModifier(userId);
                progressVO.setChangeFlag(UUID.randomUUID().toString());

                updateProgressList.add(progressVO);
            } else {
                PlanProgressVO planProgressVO = new PlanProgressVO();
                planProgressVO.setPkPlan(pkPlan);
                if (beforeDrive) {
                    planProgressVO.setProgress(100);
                    planProgressVO.setStartDate(today);
                    planProgressVO.setEndDate(today);
                } else {
                    planProgressVO.setProgress(0);
                    planProgressVO.setStartDate(today);
                    planProgressVO.setEndDate(null);
                }

                planProgressVO.setCreator(userId);
                planProgressVO.setCreationtime(today);
                planProgressVO.setFirstSubmitDate(today);
                planProgressVO.setLastSubmitDate(today);
                planProgressVO.setChangeFlag(UUID.randomUUID().toString());
                planProgressVO.setDr((byte) 0);

                insertProgressList.add(planProgressVO);
            }
        }
    }
}
